﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Globalization;

namespace Nuane.Posterous
{
	/// <summary>
	/// Represents a new posterous post.
	/// </summary>
	public class PosterousNewPost : IPosterousData
	{
		//URL
		//    * http://posterous.com/api/newpost
		//Fields
		//    * "site_id" - Optional. Id of the site to post to. If not supplied, posts to the user's default site
		//    * "media" - Optional. File data for single file.
		//    * "media[]" - Optional. File data for multiple file upload. Can be specified multiple times.
		//    * "title" - Optional. Title of post
		//    * "body" - Optional. Body of post
		//    * "autopost" - Optional. 0 or 1.
		//    * "private" - Optional. 0 or 1.
		//    * "date" - Optional. In GMT. Any parsable format. Cannot be in the future.
		//    * "tags" - Optional. Comma separate tags
		//    * "source" - Optional. The name of your application or website
		//   * "sourceLink" - Optional. Link to your application or website


		internal const int MaxMediaLength = 100 * 1000 * 1000;

		/// <summary>
		/// Gets or sets the title of this post.
		/// </summary>
		/// <value>Post title.</value>
		public string Title { get; set; }

		/// <summary>
		/// Gets or sets the body of this post.
		/// </summary>
		/// <value>Post body.</value>
		public string Body { get; set; }

		/// <summary>
		/// Gets or sets a value indicating whether to auto-post.
		/// </summary>
		/// <value>True to auto-post; false to not auto-post.</value>
		public bool AutoPost { get; set; }

		/// <summary>
		/// Gets or sets a value indicating whether the post is private.
		/// </summary>
		/// <value>True if private; false if not private.</value>
		public bool IsPrivate { get; set; }

		/// <summary>
		/// Gets or sets the UTC datetime of this post. Must not be in the future.
		/// </summary>
		/// <value>Post UTC datetime.</value>
		public DateTime? Date { get; set; }

		/// <summary>
		/// Gets or sets the tags of this post.
		/// </summary>
		/// <value>Post tags.</value>
		public string Tags { get; set; }

		/// <summary>
		/// Gets a collection of media files attached to this post.
		/// </summary>
		/// <value>Collection of media files attached to this post.</value>
		public PosterousFileCollection Files { get; private set; }

		/// <summary>
		/// Creates a new empty post. Use <see cref="PosterousSession.PublishPost(int, PosterousNewPost)"/> or <see cref="PosterousSite.PublishPost(PosterousNewPost)"/> to publish this post.
		/// </summary>
		public PosterousNewPost()
		{
			Files = new PosterousFileCollection();
		}

		/// <summary>
		/// Creates a post with the specified title and body. Use <see cref="PosterousSession.PublishPost(int, PosterousNewPost)"/> or <see cref="PosterousSite.PublishPost(PosterousNewPost)"/> to upload this post.
		/// </summary>
		/// <param name="title">Post title.</param>
		/// <param name="body">Post body.</param>
		public PosterousNewPost(string title, string body)
			: this()
		{
			Title = title;
			Body = body;
		}

		byte[] IPosterousData.ToData(string splitter, string source, Uri sourceLink, out string urlParameters)
		{
			MemoryStream buffer = new MemoryStream();
			StringBuilder parameters = new StringBuilder();

			if (!string.IsNullOrEmpty(Title))
				Helper.AppendField(buffer, splitter, "title", Title, Encoding.UTF8);

			if (!string.IsNullOrEmpty(Body))
				Helper.AppendField(buffer, splitter, "body", Body, Encoding.UTF8);

			if (AutoPost)
				parameters.Append("&autopost=1");

			if (IsPrivate)
				parameters.Append("&private=1");

			if (Date != null)
			{
				DateTime date = DateTime.Now;
				if (Date.Value < date)
					date = Date.Value;
				Helper.AppendField(buffer, splitter, "date", Helper.ToString(date), Encoding.ASCII);
			}

			if (!string.IsNullOrEmpty(Tags))
				Helper.AppendField(buffer, splitter, "tags", Tags, Encoding.UTF8);

			if (!string.IsNullOrEmpty(source))
				Helper.AppendField(buffer, splitter, "source", source, Encoding.UTF8);

			if (sourceLink != null)
				Helper.AppendField(buffer, splitter, "sourceLink", sourceLink.ToString(), Encoding.UTF8);

			long totalLength = 0;
			foreach (PosterousFile file in Files)
			{
				totalLength += file.FileLength;
			}

			if (totalLength > MaxMediaLength)
				throw new PosterousException("Post is too long.", PosterousExceptionStatus.OperationFailure);

			foreach (PosterousFile file in Files)
			{
				//TODO: this could be optimized by only reading the data later when needed
				byte[] medium = file.ReadAll();
				//Helper.AppendField(buffer, splitter, string.Format("media[{0}]", n), file.Name, medium); n++;// both variants seem to work
				Helper.AppendField(buffer, splitter, "media[]", file.Name, medium);
			}

			Helper.AppendEnd(buffer, splitter);

			urlParameters = parameters.ToString();
			return buffer.ToArray();
		}

	}

}
